package com.audaque.springboot.foshanupload.mp.config;

import cn.hutool.core.bean.BeanUtil;
import com.audaque.springboot.foshanupload.db.properties.DbProperties;
import com.audaque.springboot.foshanupload.mp.handler.impl.DiyTenantLineHandlerImpl;
import com.audaque.springboot.foshanupload.mp.injector.DiySqlInjector;
import com.audaque.springboot.foshanupload.mp.interceptor.DynamicTableNameByFieldNameInterceptor;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.binding.MapperMethod;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * @author zgb
 * @desc ...
 * @date 2021-05-20 22:08:45
 */
//Spring boot方式

@Configuration
public class MybatisPlusConfig {
    @Resource
    private DbProperties dbProperties;
    @Resource
    private DiyTenantLineHandlerImpl diyTenantLineHandlerImpl;


    // 最新版
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        String tenantId = dbProperties.getTenantId();
        //开关
        if (StringUtils.isNotBlank(tenantId)) {

            //租户拦截器放在最前面 ：private Long tenantId;
            interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(diyTenantLineHandlerImpl));
        }

        //分页

        String type = dbProperties.getType();
        if (ObjectUtils.equals(type, DbType.MYSQL.getDb())) {
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        } else if (ObjectUtils.equals(type, DbType.GAUSS.getDb())) {
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.GAUSS));
        } else if (ObjectUtils.equals(type, DbType.DM.getDb())) {
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.DM));
        } else if (ObjectUtils.equals(type, DbType.ORACLE.getDb())) {
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.ORACLE));
        } else if (ObjectUtils.equals(type, DbType.POSTGRE_SQL.getDb())) {
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));
        } else if (ObjectUtils.equals(type, DbType.SQL_SERVER.getDb())) {
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.SQL_SERVER));
        }
        //针对 update 和 delete 语句 作用: 阻止恶意的全表更新删除
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
        /**
         *  乐观锁 ：@Version
         * 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
         * 整数类型下 newVersion = oldVersion + 1
         * newVersion 会回写到 entity 中
         * 仅支持 updateById(id) 与 update(entity, wrapper) 方法
         * 在 update(entity, wrapper) 方法下, wrapper 不能复用!!!
         */

        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());

        String tableSuffixParam = dbProperties.getTableSuffixParam();
        //开关
        if (StringUtils.isNotBlank(tableSuffixParam)) {


            DynamicTableNameByFieldNameInterceptor dynamicTableNameByFieldNameInterceptor = new DynamicTableNameByFieldNameInterceptor();
            dynamicTableNameByFieldNameInterceptor.setTableNameByFieldNameHandler((sql, tableName, stringObjectMap) -> {

                if (!StringUtils.isBlank(tableSuffixParam)) {
                    Object o1 = stringObjectMap.get("_parameter");
                    Object entity = null;

                    if (o1 instanceof MapperMethod.ParamMap) {
                        Object o3 = null;
                        //查询
                        MapperMethod.ParamMap o = (MapperMethod.ParamMap) o1;

                        if (o.containsKey("list")) {
                            List o2 = (List) o.get("list");
                            o2 = ListUtils.emptyIfNull(o2);
                            if (!o2.isEmpty()) {
                                o3 = o2.get(0);
                            }
                        } else if (o.containsKey("param1")) {
                            o3 = o.get("param1");
                        }
                        if (o3 instanceof Wrapper) {
                            //query或update
                            Wrapper queryWrapper = (Wrapper) o3;
                            entity = queryWrapper.getEntity();
                        } else {
                            //update
                            entity = o3;
                        }


                    } else {
                        //insert
                        entity = o1;
                    }
                    try {

                        if (entity != null) {
                            Map<String, Object> stringObjectMap1 = BeanUtil.beanToMap(entity);
                            Object o = stringObjectMap1.get(tableSuffixParam);
                            if (o != null) {
                                return tableName + "_" + o;
                            }

                        }

                    } catch (Exception e) {
                        return tableName;
                    }
                }

                return tableName;
            });
            interceptor.addInnerInterceptor(dynamicTableNameByFieldNameInterceptor);

        }




        return interceptor;
    }


    @Bean
    public DiySqlInjector sqlInjector() {
        return new DiySqlInjector(diyTenantLineHandlerImpl);
    }


}

